﻿using System.Text;

namespace mei_cs.comm;

public class Logger
{
    public enum Level
    {
        Debug,
        Info,
        Warning,
        Error,
    }

    private readonly string _name;
    private readonly Level _consoleLevel;
    private readonly string _fileName;
    private readonly Level _fileLevel;

    private static readonly Dictionary<string, Logger> Instances = new();

    private Logger(string name, Level consoleLevel, string fileName, Level fileLevel)
    {
        _name = name;
        _consoleLevel = consoleLevel;
        _fileName = fileName;
        _fileLevel = fileLevel;
        
        Console.InputEncoding = Encoding.UTF8;
        Console.OutputEncoding = Encoding.UTF8;
    }

    // ReSharper disable once UnusedMember.Global
    public static Logger GetLogger(string name, Level level)
    {
        return GetLogger(name, level, name + ".txt", level);
    }

    // ReSharper disable once UnusedMember.Global
    public static Logger GetLogger(string name, Level consoleLevel, Level fileLevel)
    {
        return GetLogger(name, consoleLevel, name + ".txt", fileLevel);
    }

    // ReSharper disable once MemberCanBePrivate.Global
    public static Logger GetLogger(string name, Level consoleLevel, string fileName, Level fileLevel)
    {
        if (Instances.TryGetValue(name, out var instance))
        {
            return instance;
        }

        return Instances[name] = new Logger(name, consoleLevel, fileName, fileLevel);
    }

    private static string LogPath(string fileName)
    {
        const string dir = "log";
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }

        return Path.Combine(dir, fileName);
    }

    private void Log(Level level, string message)
    {
        if (level < _consoleLevel && level < _fileLevel)
        {
            return;
        }

        var formattedMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {_name} {level}: {message}";
        if (level >= _consoleLevel)
        {
            Console.WriteLine(formattedMessage);
        }

        if (level >= _fileLevel)
        {
            File.AppendAllText(LogPath(_fileName), "\r\n" + formattedMessage);
        }
    }

    public void Debug(string message)
    {
        Log(Level.Debug, message);
    }

    public void Info(string message)
    {
        Log(Level.Info, message);
    }

    public void Warning(string message)
    {
        Log(Level.Warning, message);
    }

    public void Error(string message)
    {
        Log(Level.Error, message);
    }
}